﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.Server;
using System.Threading;

namespace TeamReview.Services
{
	internal class MemberReader : IComparable
	{

		private Identity _identity;
		private IGroupSecurityService _gss;
		private List<string> _memberNames;

		public Identity Identity
		{
			get { return _identity; }
		}

		public List<string> MemberNames
		{
			get { return _memberNames; }
		}
		public IGroupSecurityService Gss
		{
			get { return _gss; }
		}

		public MemberReader(Identity identity, IGroupSecurityService gss)
		{
			_memberNames = new List<String>();
			_identity = identity;
			_gss = gss;
		}

		public void Read()
		{
			Identity directMembers = _gss.ReadIdentity(SearchFactor.Sid, _identity.Sid, QueryMembership.Expanded);

			ManualResetEvent[] doneEvents = new ManualResetEvent[directMembers.Members.GetLength(0)];
			IdentityReader[] readers = new IdentityReader[doneEvents.Length];
			int i = 0;
			foreach (string memberSid in directMembers.Members)
			{
				doneEvents[i] = new ManualResetEvent(false);
				IdentityReader reader = new IdentityReader(memberSid, this, doneEvents[i]);
				readers[i] = reader;
				ThreadPool.QueueUserWorkItem(reader.ThreadPoolCallback);
				i++;
			}

			//can only wait for 64 at a time
			for (int j = 0; j < doneEvents.Length; j += 64)
			{
				int max = Math.Min((j + 64), doneEvents.Length);
				ManualResetEvent[] partEvents = new ManualResetEvent[(max-j)];
				Array.Copy(doneEvents, j, partEvents, 0, (max-j));
				WaitHandle.WaitAll(partEvents);
			}

		}

		private class IdentityReader
		{
			private String _memberSid;
			private MemberReader _memberReader;
			private ManualResetEvent _doneEvent;
			public string MemberSid
			{
				get { return _memberSid; }
			}

			public ManualResetEvent DoneEvent
			{
				get
				{
					return _doneEvent;
				}
			}


			public IdentityReader(string memberSid, MemberReader memberReader, ManualResetEvent doneEvent)
			{
				_memberSid = memberSid;
				_memberReader = memberReader;
				_doneEvent = doneEvent;
			}

			public void ThreadPoolCallback(Object threadContext)
			{
				Identity member = _memberReader.Gss.ReadIdentity(SearchFactor.Sid, _memberSid, QueryMembership.None);

				if (!member.SecurityGroup && member.Type != IdentityType.WindowsGroup
					&& member.Type != IdentityType.ApplicationGroup)
				{
					if (!_memberReader.MemberNames.Contains(member.DisplayName))
					{
						lock (_memberReader.MemberNames)
						{
							if (!_memberReader.MemberNames.Contains(member.DisplayName))
								_memberReader.MemberNames.Add(member.DisplayName);
						}
					}

				}

                _doneEvent.Set();
			}
		}

		#region IComparable Members

		public int CompareTo(object obj)
		{
			if (obj is MemberReader)
			{
				MemberReader mr2 = (MemberReader)obj;
				return Identity.DisplayName.CompareTo(mr2.Identity.DisplayName);
			}
			else
				throw new ArgumentException("Object is not a MemberReader.");

		}

		#endregion
	}
}
